package edu.ncsu.csc.ip.server.protocol;

import java.net.Socket;
import java.util.Date;

import edu.ncsu.csc.ip.common.HeaderBean;
import edu.ncsu.csc.ip.common.NetworkUtils;
import edu.ncsu.csc.ip.common.Protocol;
import edu.ncsu.csc.ip.common.serializer.BeanSerializer;
import edu.ncsu.csc.ip.server.ClientBean;
import edu.ncsu.csc.ip.server.ClientIndex;

/**
 * Class <code></code>
 * 
 * 
 * 
 * @author Moin Ayazifar <mayazif@ncsu.edu>
 * @author Steven Elliott <sdelliot@ncsu.edu>
 * 
 */

public class ProtocolServerImpl implements Protocol {

	//private State state = State.IDLE;

	private Socket socket;

	public ProtocolServerImpl(Socket socket) {
		this.setSocket(socket);
	}

	/** THE MESSAGE REGISTER */
	public static final String REGISTER = "REGISTER";
	public static final String LEAVE = "LEAVE";
	public static final String PQUERY = "PQUERY";
	public static final String KEEPALIVE = "KEEPALIVE";

	public static final String OK = "OK";
	public static final String ERROR = "ERROR";

	/**
	 * @param cookie
	 *            the cookie to set
	 */

	public String parseCommand(String message) {

		return null;

	}

	/**
	 * @param cookie
	 *            the cookie to set
	 */

	public String parseMessage(String message) {
		if (message.toUpperCase().startsWith(REGISTER)) {
			return register(message);
		} else if (message.startsWith(LEAVE)) {
			return leave(message);
		} else if (message.startsWith(PQUERY)) {
			return pQuery(message);
		} else if (message.startsWith(KEEPALIVE)) {
			return keepAlive(message);
		} else {
			return null;
		}
	}

	/**
	 * @param cookie
	 *            the cookie to set
	 */

	public String register(String message) {
		String[] messages = message.split(HEADER_SPLITTER);

		try {
			BeanSerializer<ClientBean> bSerializer = new BeanSerializer<ClientBean>(
					ClientBean.class);
			ClientBean clientBean = bSerializer.getBean(messages[1]);

			if (clientBean.getCookie() != null
					&& ClientIndex.getInstance().getclientIndexMap()
							.containsKey(clientBean.getCookie())) {
				clientBean = ClientIndex.getInstance().getClient(clientBean.getCookie());
				keepClientAlive(clientBean);
			} else {
				clientBean.setActiveFlag(true);
				clientBean.setTtl(MAX_TTL);
				clientBean.setActivityCount(1);
				clientBean.setIpAddress(NetworkUtils.getRemoteAdress(socket).getHostAddress());
				clientBean.setHostname(NetworkUtils.getRemoteAdress(socket).getHostName());
				clientBean.setLastAccessDate(new Date());
				ClientIndex.getInstance().addClient(clientBean);
			}

			return getHeader(OK) + HEADER_SPLITTER
					+ bSerializer.getString(clientBean);

		} catch (Exception e) {
			return getHeader(ERROR) + HEADER_SPLITTER + e.getMessage();
		}
	}

	public String leave(String message) {
		String[] messages = message.split(HEADER_SPLITTER);

		try {
			BeanSerializer<ClientBean> bSerializer = new BeanSerializer<ClientBean>(
					ClientBean.class);
			ClientBean clientBean = bSerializer.getBean(messages[1]);
			if (clientBean.getCookie() != null
					&& ClientIndex.getInstance().getclientIndexMap()
							.containsKey(clientBean.getCookie())) {
				ClientIndex.getInstance().getclientIndexMap()
						.remove(clientBean.getCookie());
				return getHeader(OK) + HEADER_SPLITTER
						+ "Client Removed Successfully!";
			} else {
				return getHeader(ERROR) + HEADER_SPLITTER
						+ "Unregistered Client Cannot be Removed!";
			}
		} catch (Exception e) {
			return getHeader(ERROR) + HEADER_SPLITTER + e.getMessage();
		}
	}

	/**
	 * @return the state
	 */
	public String pQuery(String message) {
		String[] messages = message.split(HEADER_SPLITTER);
		try {
			BeanSerializer<ClientBean> bSerializer = new BeanSerializer<ClientBean>(
					ClientBean.class);
			ClientBean clientBean = bSerializer.getBean(messages[1]);
			if (clientBean.getCookie() != null
					&& ClientIndex.getInstance().getclientIndexMap()
							.containsKey(clientBean.getCookie())) {
				clientBean = ClientIndex.getInstance().getClient(clientBean.getCookie());
				keepClientAlive(clientBean);
				return getHeader(PQUERY) + HEADER_SPLITTER
						+ bSerializer.getString(ClientIndex.getInstance().getActiveClients(clientBean.getCookie()));
			} else {
				return getHeader(ERROR) + HEADER_SPLITTER
						+ "Unregistered Client Cannot send KeapAlive Command!";
			}
		} catch (Exception e) {
			return getHeader(ERROR) + HEADER_SPLITTER + e.getMessage();
		}
	}

	/**
	 * @param state
	 *            the state to set
	 */
	public String keepAlive(String message) {
		String[] messages = message.split(HEADER_SPLITTER);
		try {
			BeanSerializer<ClientBean> bSerializer = new BeanSerializer<ClientBean>(
					ClientBean.class);
			ClientBean clientBean = bSerializer.getBean(messages[1]);
			if (clientBean.getCookie() != null
					&& ClientIndex.getInstance().getclientIndexMap()
							.containsKey(clientBean.getCookie())) {
				clientBean = ClientIndex.getInstance().getClient(clientBean.getCookie());
				keepClientAlive(clientBean);
				return getHeader(OK) + HEADER_SPLITTER
						+ "Client TTL updated to:" + MAX_TTL;
			} else {
				return getHeader(ERROR) + HEADER_SPLITTER
						+ "Unregistered Client Cannot send KeapAlive Command!";
			}
		} catch (Exception e) {
			return getHeader(ERROR) + HEADER_SPLITTER + e.getMessage();
		}
	}

	String getHeader(String message) {

		HeaderBean headerBean = new HeaderBean();
		headerBean.setMessage(message);
		headerBean.setOs(NetworkUtils.getOsName());
		headerBean.setProtocol(PROTOCOL_VERSION);
		headerBean.setDate(new Date());
		headerBean.setAddress(NetworkUtils.getLocalAdress(socket).getHostAddress());
		headerBean.setHostname(NetworkUtils.getLocalAdress(socket).getHostName());
		BeanSerializer<HeaderBean> bSerializer = new BeanSerializer<HeaderBean>(
				HeaderBean.class);
		String headerString = bSerializer.getString(headerBean);
		String headerMessage = headerString.substring(HeaderBean.TRIM_STRING
				.length());
		return headerMessage;

	}

	HeaderBean getHeaderBean(String headerMessage) {

		String headerString = HeaderBean.TRIM_STRING + headerMessage;
		BeanSerializer<HeaderBean> bSerializer = new BeanSerializer<HeaderBean>(
				HeaderBean.class);
		return bSerializer.getBean(headerString);

	}

	
	private void keepClientAlive(ClientBean clientBean){
		clientBean.setTtl(MAX_TTL);
		clientBean.setActiveFlag(true);
		clientBean.setLastAccessDate(new Date());
		clientBean.increaseActivityCount();
	}
	
	
	/**
	 * @return the socket
	 */
	@Override
	public Socket getSocket() {
		return socket;
	}

	/**
	 * @param socket
	 *            the socket to set
	 */
	@Override
	public void setSocket(Socket socket) {
		this.socket = socket;
	}

	@Override
	public boolean isRFCCommand(String message) {
		return false;
	}

	@Override
	public boolean isFileTransferCommand(String command) {
		return false;
	}

}
